#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <NewStack.h>

#define $$(First_Part_Of_The_Function, Object)  First_Part_Of_The_Function##_Is_Fine(Object)

//<Creating a stack, using initial parametres

int Stack_Create(struct Stack* Stack_Itself, long Maximal_Size)
{
    Stack_Itself->Maximal_Size = Maximal_Size;
    Stack_Itself->Value =calloc(Maximal_Size, sizeof(*(Stack_Itself->Value)));
    assert(Stack_Itself->Value);
    Stack_Itself->Counter = 0;
    return 0;
}

//<Destroy the stack

int Stack_Destruct(struct Stack* Stack_Itself)
{
    Stack_Itself->Counter = 0;
    Stack_Itself->Maximal_Size = 0;
    free(Stack_Itself->Value);
    Stack_Itself->Value = NULL;
    Stack_Itself=NULL;
    Stack_Error_Number=No_Stack;

    return 0;
}

//<Pushing the info into the stack

int Stack_Push(struct Stack* Stack_Itself, double Put_In_The_Data)
{
    if (!$$(Stack, Stack_Itself))
    {
        Stack_Dump(Stack_Itself);
        printf("Stack is not fine before applying the function Stack_Push \n");
        assert(NULL);
    }
    Stack_Itself->Counter++;
    if (!$$(Stack, Stack_Itself))
    {
        Stack_Dump(Stack_Itself);
        printf("Stack's not fine while applying the function Stack_Push \n");
        assert(NULL);
    }
    Stack_Itself->Value[Stack_Itself->Counter-1] = Put_In_The_Data;
    if (!$$(Stack, Stack_Itself))
    {
        Stack_Dump(Stack_Itself);
        printf("Stack's not fine after applying the function Stack_Push\n");
        assert(NULL);
    }
    return 0;
}

//Pop the stack.
double Stack_Pop(struct Stack* Stack_Itself)
{
    if (!$$(Stack, Stack_Itself))
    {
        Stack_Dump(Stack_Itself);
        printf("Stack is not fine in the beginning of Stack_Pop\n");
        assert(NULL);
    }
    Stack_Itself->Counter--;
    if (!$$(Stack, Stack_Itself))
    {
        Stack_Dump(Stack_Itself);
        printf("Stack is not fine  Stack_Pop\n");
        assert(NULL);
    }

    double Returning_Value = Stack_Itself->Value[Stack_Itself->Counter];
    if (!$$(Stack, Stack_Itself))
    {
        Stack_Dump(Stack_Itself);
        printf("Stack isn't fine after applying the function Stack_Pop\n");
        assert(NULL);
    }
    return Returning_Value;
}


//<Dumping function

int Stack_Dump(struct Stack* Stack_Itself)
{
    Stack_Init_Error("What's wrong with the stack");
    printf( "stack is ");
    if ($$(Stack, Stack_Itself))
    {
        printf( "fine!");
    }
    else
    {
        printf( "not valid!");
    }
    printf("| [0x%lx] \n", (long)Stack_Itself);
    printf("|=================================|\n");
    printf("|      Options of the stack       |\n");
    printf("|---------------------------------|\n");
    printf("|Counter = %23li|\n|Maximal_Size = %18li|\n", Stack_Itself->Counter, Stack_Itself->Maximal_Size);
    printf("|=================================|\n");
    printf("|       Values of the stack       |\n");
    printf("|---------------------------------|\n");
    if (Stack_Itself->Value)
    {
        long i;
        for (i = 0; i < Stack_Itself->Maximal_Size;i++)
        {
            printf( "|Value{%3li}=%22.10lg|",i,Stack_Itself->Value[i]);
            if (i >= Stack_Itself->Counter)
            {
                printf( "<--Not used yet");
            }
            printf( "\n");
        }
    }
    printf( "|=================================|\n");
    return 0;
}

//<This Function checks if the Stack is fine

int Stack_Is_Fine(struct Stack* Stack_Itself)
{
    if (!Stack_Itself)
    {
        Stack_Error_Number = No_Stack;
        return 0;
    }
    else if (!Stack_Itself->Value)
    {
        Stack_Error_Number = No_Value;
        return 0;
    }
    else if (Stack_Itself->Counter > Stack_Itself->Maximal_Size)
    {
        Stack_Error_Number = Stack_Overflow;
        return 0;
    }
    else if (Stack_Itself->Counter < 0)
    {
        Stack_Error_Number = Stack_Underflow;
        return 0;
    }
    return 1;
}




//Typing into a console

int Stack_Init_Error(char* Init_Message)
{
    char* Final_Message = "";
    assert(Final_Message);
    switch (Stack_Error_Number)
    {
        case Stack_Fine:        Final_Message = "Nothing ";
                                break;
        case No_Stack:          Final_Message = "No Stack ";
                                break;
        case Stack_Overflow:    Final_Message = "Stack overflow";
                                break;
        case Stack_Underflow:   Final_Message = "Stack underflow ()";
                                break;
        case No_Value:          Final_Message = "No Value";
                                break;
    }
    printf("-%s? -%s, ", Init_Message, Final_Message);
    Final_Message = NULL;
    return 0;
}


//An example to check how the program works

int main(void)
{
    long Stack_Size = 10;
    double value = 10000000.666;
    struct Stack *NewStack = (struct Stack*)calloc(1,sizeof(struct Stack));
    struct Stack *OneMore;
    Stack_Create(NewStack, Stack_Size);
    Stack_Dump(NewStack);
    Stack_Destruct(NewStack);
    Stack_Dump(NewStack);

    printf("Hello World!\n");

    return 0;
}

